/**
 * 移动端键盘处理工具
 * 解决输入框失去焦点或点击键盘发送时收起键盘
 * 兼容iOS Safari和Android Edge浏览器
 */
import { onMounted, Ref, nextTick, onBeforeUnmount } from 'vue'

// 记录当前滚动位置的全局变量
let scrollPosition = 0
// 存储全局滚动事件处理函数的引用
let globalScrollHandler: ((e: Event) => void) | null = null
// 存储触摸事件处理函数的引用
let globalTouchStartHandler: ((e: TouchEvent) => void) | null = null
let globalTouchMoveHandler: ((e: TouchEvent) => void) | null = null
// 标记键盘是否处于打开状态
let isKeyboardVisible = false
// 记录触摸开始的位置
let touchStartY = 0
// 记录最后一个获得焦点的输入元素
let lastFocusedInput: HTMLInputElement | HTMLTextAreaElement | null = null
// 记录键盘状态检测的定时器
let keyboardCheckInterval: number | null = null;

/**
 * 保存当前滚动位置
 */
const saveScrollPosition = (): void => {
  scrollPosition = window.scrollY || window.pageYOffset
}

/**
 * 恢复保存的滚动位置
 */
const restoreScrollPosition = (): void => {
  window.scrollTo({
    top: scrollPosition,
    behavior: 'auto' // 使用auto避免平滑滚动的视觉效果
  })
}

/**
 * 标记键盘打开状态并记录当前输入元素
 */
const markKeyboardOpen = (inputElement?: HTMLInputElement | HTMLTextAreaElement): void => {
  isKeyboardVisible = true;
  if (inputElement) {
    lastFocusedInput = inputElement;
  }
  
  // 启动键盘状态检测
  startKeyboardCheck();
}

/**
 * 标记键盘关闭状态
 */
const markKeyboardClosed = (): void => {
  isKeyboardVisible = false;
  // 停止键盘状态检测
  stopKeyboardCheck();
}

/**
 * 启动键盘状态检测定时器
 */
const startKeyboardCheck = (): void => {
  // 如果已存在定时器，先清除
  stopKeyboardCheck();
  
  // 创建新的定时器，每200ms检查一次键盘状态
  keyboardCheckInterval = window.setInterval(() => {
    // 检查当前是否有输入框获得焦点
    const activeElement = document.activeElement;
    if (
      !(activeElement instanceof HTMLInputElement) && 
      !(activeElement instanceof HTMLTextAreaElement)
    ) {
      // 如果没有输入框获得焦点，但键盘状态为打开，则关闭键盘
      if (isKeyboardVisible) {
        markKeyboardClosed();
        closeKeyboard(isEdgeBrowser());
      }
    }
  }, 200);
}

/**
 * 停止键盘状态检测定时器
 */
const stopKeyboardCheck = (): void => {
  if (keyboardCheckInterval !== null) {
    clearInterval(keyboardCheckInterval);
    keyboardCheckInterval = null;
  }
}

/**
 * 检查键盘是否打开
 */
export const isKeyboardOpen = (): boolean => {
  return isKeyboardVisible;
}

/**
 * 强制关闭移动端虚拟键盘
 * @param smooth 是否平滑关闭，避免闪动
 */
export const closeKeyboard = (smooth = false): void => {
  // 标记键盘关闭
  markKeyboardClosed();
  
  // 使当前活跃的输入元素失去焦点
  const activeElement = document.activeElement;
  if (
    activeElement instanceof HTMLInputElement || 
    activeElement instanceof HTMLTextAreaElement
  ) {
    activeElement.blur();
  }
  
  // 如果有记录的最后一个获得焦点的输入元素，也让它失去焦点
  if (lastFocusedInput) {
    lastFocusedInput.blur();
    lastFocusedInput = null;
  }
  
  // Edge浏览器中平滑关闭，避免闪动
  if (smooth && isEdgeBrowser()) {
    // 保存当前滚动位置
    saveScrollPosition()
    
    // 先禁止滚动，避免闪动
    document.body.style.overflow = 'hidden'
    document.body.style.height = '100%'
    
    // 使用更长的延迟，让浏览器有时间处理UI
    setTimeout(() => {
      doCloseKeyboard()
      
      // 立即尝试再次关闭键盘，以应对某些顽固的情况
      setTimeout(doCloseKeyboard, 50)
      
      // 恢复滚动位置
      setTimeout(() => {
        // 恢复滚动
        document.body.style.overflow = ''
        document.body.style.height = ''
        
        // 恢复滚动位置
        restoreScrollPosition()
        
        // 最后再次确保键盘已关闭
        setTimeout(doCloseKeyboard, 50)
      }, 100)
    }, 300)
  } else {
    doCloseKeyboard()
    // 延迟再次尝试关闭，以应对某些键盘关闭不彻底的情况
    setTimeout(doCloseKeyboard, 100)
  }
}

/**
 * 实际执行键盘关闭操作
 */
const doCloseKeyboard = (): void => {
  // 创建一个临时输入元素
  const tempInput = document.createElement('input')
  // 设置为不可见
  tempInput.style.position = 'absolute'
  tempInput.style.opacity = '0'
  tempInput.style.height = '0'
  tempInput.style.width = '0'
  tempInput.style.pointerEvents = 'none' // 防止意外交互
  tempInput.style.top = '-9999px' // 放在屏幕外
  tempInput.style.left = '-9999px' // 放在屏幕外
  tempInput.setAttribute('readonly', 'readonly') // 避免某些浏览器的自动聚焦行为
  
  // 添加到DOM
  document.body.appendChild(tempInput)
  // 先获取焦点
  tempInput.focus()
  // 立即失去焦点关闭键盘
  tempInput.blur()
  // 移除临时元素
  document.body.removeChild(tempInput)
}

/**
 * 检测是否为iOS设备
 */
export const isIOS = (): boolean => {
  return /iPad|iPhone|iPod/.test(navigator.userAgent) || 
    (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)
}

/**
 * 检测是否为安卓设备
 */
export const isAndroid = (): boolean => {
  return /Android/.test(navigator.userAgent)
}

/**
 * 检测是否为Edge浏览器
 */
export const isEdgeBrowser = (): boolean => {
  return /Edg\/|Edge\//.test(navigator.userAgent)
}

/**
 * 阻止页面滚动临时锁定
 */
const lockPageScroll = (): void => {
  // 保存当前滚动位置
  saveScrollPosition()
  
  // 临时锁定滚动
  document.body.style.overflow = 'hidden'
  document.body.style.position = 'fixed'
  document.body.style.width = '100%'
  document.body.style.top = `-${scrollPosition}px`
}

/**
 * 解锁页面滚动
 */
const unlockPageScroll = (): void => {
  // 恢复滚动
  document.body.style.overflow = ''
  document.body.style.position = ''
  document.body.style.width = ''
  document.body.style.top = ''
  
  // 恢复滚动位置
  window.scrollTo(0, scrollPosition)
}

/**
 * 注册滚动监听，在滚动时自动关闭键盘
 */
export const registerScrollToHideKeyboard = (): (() => void) => {
  // 触摸开始事件
  const touchStartHandler = (e: TouchEvent) => {
    if (e.touches.length === 1) {
      // 记录触摸开始位置
      touchStartY = e.touches[0].clientY;
    }
  }
  
  // 触摸移动事件
  const touchMoveHandler = (e: TouchEvent) => {
    if (e.touches.length === 1) {
      // 计算移动距离
      const touchMoveY = e.touches[0].clientY;
      const deltaY = Math.abs(touchMoveY - touchStartY);
      
      // 降低触发阈值，任何滚动都会关闭键盘
      if (deltaY > 5) {
        // 强制关闭键盘，不再检查键盘状态
        const activeElement = document.activeElement;
        if (
          activeElement instanceof HTMLInputElement || 
          activeElement instanceof HTMLTextAreaElement
        ) {
          activeElement.blur();
          closeKeyboard(isEdgeBrowser());
        } else if (lastFocusedInput) {
          lastFocusedInput.blur();
          closeKeyboard(isEdgeBrowser());
        }
        
        // 确保键盘状态被标记为关闭
        markKeyboardClosed();
      }
    }
  }
  
  // 滚动事件处理 - 使用捕获阶段以确保先于其他处理器执行
  const scrollHandler = (e: Event) => {
    // 无需检查键盘状态，任何滚动都尝试关闭键盘
    const activeElement = document.activeElement;
    if (
      activeElement instanceof HTMLInputElement || 
      activeElement instanceof HTMLTextAreaElement
    ) {
      activeElement.blur();
      closeKeyboard(isEdgeBrowser());
    } else if (lastFocusedInput) {
      lastFocusedInput.blur();
      closeKeyboard(isEdgeBrowser());
    }
    
    // 确保键盘状态被标记为关闭
    markKeyboardClosed();
  }
  
  // 保存全局引用，方便后续移除
  globalScrollHandler = scrollHandler;
  globalTouchStartHandler = touchStartHandler;
  globalTouchMoveHandler = touchMoveHandler;
  
  // 添加事件监听 - 使用捕获阶段以确保先于其他处理器执行
  window.addEventListener('scroll', scrollHandler, { passive: true, capture: true });
  document.addEventListener('scroll', scrollHandler, { passive: true, capture: true });
  window.addEventListener('touchstart', touchStartHandler, { passive: true });
  window.addEventListener('touchmove', touchMoveHandler, { passive: true });
  
  // 监听窗口大小变化，这通常发生在键盘弹出/收起时
  window.addEventListener('resize', () => {
    // 如果键盘处于打开状态且检测到可能是键盘收起引起的大小变化
    if (isKeyboardOpen()) {
      // 延迟检查，避免误判
      setTimeout(() => {
        // 再次检查是否有活跃的输入元素
        const activeElement = document.activeElement;
        if (
          !(activeElement instanceof HTMLInputElement) && 
          !(activeElement instanceof HTMLTextAreaElement)
        ) {
          // 如果没有活跃的输入元素，认为键盘已收起
          markKeyboardClosed();
        }
      }, 300);
    }
  });
  
  // 返回清理函数
  return () => {
    // 移除事件监听
    if (globalScrollHandler) {
      window.removeEventListener('scroll', globalScrollHandler, { capture: true } as EventListenerOptions);
      document.removeEventListener('scroll', globalScrollHandler, { capture: true } as EventListenerOptions);
      globalScrollHandler = null;
    }
    if (globalTouchStartHandler) {
      window.removeEventListener('touchstart', globalTouchStartHandler);
      globalTouchStartHandler = null;
    }
    if (globalTouchMoveHandler) {
      window.removeEventListener('touchmove', globalTouchMoveHandler);
      globalTouchMoveHandler = null;
    }
    
    // 停止键盘状态检测
    stopKeyboardCheck();
  }
}

/**
 * 注册键盘处理事件
 * @param inputElement 输入框元素
 * @param sendButton 发送按钮元素(可选)
 */
export const useKeyboardHandler = (
  inputElement: HTMLInputElement | HTMLTextAreaElement, 
  sendButton?: HTMLElement
): void => {
  if (!inputElement) {
    console.warn('输入元素不存在');
    return;
  }

  // 是否为Edge浏览器
  const isEdge = isEdgeBrowser();
  
  // 监听输入框聚焦事件，标记键盘打开
  inputElement.addEventListener('focus', () => {
    markKeyboardOpen(inputElement);
  });

  // 处理输入框失去焦点
  inputElement.addEventListener('blur', () => {
    // 不立即标记键盘关闭，因为可能是切换到了另一个输入框
    // 通过定时器检查来处理这种情况
    
    // Edge浏览器的特殊处理
    if (isEdge) {
      // 保存滚动位置
      saveScrollPosition()
      
      // 锁定滚动，防止闪动
      lockPageScroll()
      
      // 延迟执行关闭键盘
      setTimeout(() => {
        closeKeyboard(true)
        
        // 解锁滚动
        setTimeout(() => {
          unlockPageScroll()
        }, 100)
      }, 200)
    } else {
      // 其他浏览器正常处理
      setTimeout(() => {
        closeKeyboard()
      }, 100)
    }
  });

  // 处理键盘按键事件（安卓"前往"和iOS"换行"键）
  inputElement.addEventListener('keyup', (event: KeyboardEvent) => {
    // 回车键或换行键
    if (event.key === 'Enter') {
      // 阻止默认行为
      event.preventDefault()
      
      // Edge浏览器特殊处理
      if (isEdge) {
        // 保存滚动位置
        saveScrollPosition()
        
        // 锁定滚动，防止闪动
        lockPageScroll()
        
        // 先触发表单提交事件（如果有表单）
        if (inputElement.form) {
          const submitEvent = new Event('submit', { bubbles: true })
          inputElement.form.dispatchEvent(submitEvent)
        }
        
        // 延迟执行关闭键盘
        setTimeout(() => {
          // 非文本域（textarea）输入框，回车时关闭键盘
          if (!(inputElement instanceof HTMLTextAreaElement)) {
            document.activeElement instanceof HTMLElement && document.activeElement.blur()
            closeKeyboard(true)
          }
          
          // 解锁滚动
          setTimeout(() => {
            unlockPageScroll()
          }, 100)
        }, 200)
      } else {
        // 其他浏览器正常处理
        setTimeout(() => {
          // 非文本域（textarea）输入框，回车时关闭键盘
          if (!(inputElement instanceof HTMLTextAreaElement)) {
            inputElement.blur()
            closeKeyboard()
          }
        }, 50)
      }
    }
  })

  // 处理输入完成事件（适用于移动端虚拟键盘的"完成"/"前往"按钮）
  inputElement.addEventListener('keydown', (event: KeyboardEvent) => {
    // 回车键处理
    if (event.key === 'Enter' && !event.shiftKey) {
      // 处理非文本域的回车事件
      if (!(inputElement instanceof HTMLTextAreaElement)) {
        // Edge浏览器特殊处理
        if (isEdge) {
          // 阻止默认行为
          event.preventDefault()
          
          // 保存滚动位置
          saveScrollPosition()
          
          // 锁定滚动，防止闪动
          lockPageScroll()
          
          // 触发表单提交事件（如果有表单）
          if (inputElement.form) {
            const submitEvent = new Event('submit', { bubbles: true })
            inputElement.form.dispatchEvent(submitEvent)
          }
          
          // 延迟执行关闭键盘
          setTimeout(() => {
            inputElement.blur()
            closeKeyboard(true)
            
            // 解锁滚动
            setTimeout(() => {
              unlockPageScroll()
            }, 100)
          }, 200)
        } else {
          // 其他浏览器正常处理
          // 触发提交事件
          if (inputElement.form) {
            const submitEvent = new Event('submit', { bubbles: true })
            inputElement.form.dispatchEvent(submitEvent)
          }
          
          // 关闭键盘
          setTimeout(() => {
            inputElement.blur()
            closeKeyboard()
          }, 50)
        }
      }
    }
  })

  // 表单提交事件处理
  if (inputElement.form) {
    inputElement.form.addEventListener('submit', (event) => {
      // 防止表单默认提交行为（如果需要）
      event.preventDefault()
      
      // Edge浏览器特殊处理
      if (isEdge) {
        // 保存滚动位置
        saveScrollPosition()
        
        // 锁定滚动，防止闪动
        lockPageScroll()
        
        // 延迟执行关闭键盘
        setTimeout(() => {
          inputElement.blur()
          closeKeyboard(true)
          
          // 解锁滚动
          setTimeout(() => {
            unlockPageScroll()
          }, 100)
        }, 200)
      } else {
        // 其他浏览器正常处理
        inputElement.blur()
        closeKeyboard()
      }
    })
  }

  // 如果提供了发送按钮，添加点击事件
  if (sendButton) {
    sendButton.addEventListener('click', () => {
      // Edge浏览器特殊处理
      if (isEdge) {
        // 保存滚动位置
        saveScrollPosition()
        
        // 锁定滚动，防止闪动
        lockPageScroll()
        
        // 延迟执行关闭键盘
        setTimeout(() => {
          // 先使输入框失去焦点
          inputElement.blur()
          // 强制关闭键盘
          closeKeyboard(true)
          
          // 解锁滚动
          setTimeout(() => {
            unlockPageScroll()
          }, 100)
        }, 200)
      } else {
        // 其他浏览器正常处理
        // 先使输入框失去焦点
        inputElement.blur()
        // 强制关闭键盘
        closeKeyboard()
      }
    })
  }
}

/**
 * 处理多个输入框的键盘事件
 * @param inputElements 输入框元素数组
 * @param sendButton 发送按钮元素(可选)
 */
export const useMultipleKeyboardHandlers = (
  inputElements: (HTMLInputElement | HTMLTextAreaElement)[], 
  sendButton?: HTMLElement
): void => {
  if (!inputElements || inputElements.length === 0) {
    console.warn('没有输入元素')
    return
  }

  // 为每个输入框注册事件
  inputElements.forEach(inputElement => {
    if (inputElement) {
      useKeyboardHandler(inputElement, sendButton)
    }
  })
}

/**
 * Vue组合式API的键盘处理钩子
 * @param options 配置选项
 * @returns 包含关闭键盘方法的对象
 */
export const useKeyboard = (options: {
  // 单个输入框的ref引用
  inputRef?: Ref<HTMLInputElement | HTMLTextAreaElement | null>,
  // 多个输入框的ref引用数组
  inputRefs?: Ref<HTMLInputElement | HTMLTextAreaElement | null>[],
  // 发送按钮的ref引用
  sendBtnRef?: Ref<HTMLElement | null>,
  // 是否自动注册事件
  autoRegister?: boolean,
  // 是否在滚动时自动隐藏键盘
  hideOnScroll?: boolean
} = {}) => {
  const { 
    inputRef, 
    inputRefs,
    sendBtnRef, 
    autoRegister = true,
    hideOnScroll = true 
  } = options
  
  // 是否为Edge浏览器
  const isEdge = isEdgeBrowser()
  
  // 清理函数
  let cleanup: (() => void) | null = null
  // 滚动清理函数
  let scrollCleanup: (() => void) | null = null

  // 关闭键盘方法
  const hideKeyboard = () => {
    // 确保键盘状态被标记为关闭
    markKeyboardClosed()
    
    // Edge浏览器特殊处理
    if (isEdge) {
      // 保存滚动位置
      saveScrollPosition()
      
      // 锁定滚动，防止闪动
      lockPageScroll()
      
      // 延迟执行关闭键盘
      setTimeout(() => {
        closeKeyboard(true)
        
        // 解锁滚动
        setTimeout(() => {
          unlockPageScroll()
        }, 100)
      }, 200)
    } else {
      // 其他浏览器正常处理
      closeKeyboard()
    }
  }

  // 注册事件处理
  const registerEvents = () => {
    // 处理多个输入框的情况
    if (inputRefs && inputRefs.length > 0) {
      // 收集所有有效的输入元素
      const validInputElements = inputRefs
        .map(ref => ref.value)
        .filter((el): el is HTMLInputElement | HTMLTextAreaElement => el !== null)
      
      if (validInputElements.length === 0) {
        console.warn('没有有效的输入元素ref')
        return
      }
      
      // 为所有输入元素注册事件
      useMultipleKeyboardHandlers(
        validInputElements,
        sendBtnRef?.value || undefined
      )
    } 
    // 处理单个输入框的情况
    else if (inputRef?.value) {
      useKeyboardHandler(
        inputRef.value,
        sendBtnRef?.value || undefined
      )
    } else {
      console.warn('没有提供有效的输入元素ref')
    }
    
    // 如果启用了滚动隐藏键盘功能，立即注册
    if (hideOnScroll && !scrollCleanup) {
      scrollCleanup = registerScrollToHideKeyboard()
    }
  }

  // 如果设置了自动注册且提供了输入框ref
  if (autoRegister && (inputRef || (inputRefs && inputRefs.length > 0))) {
    // 在组件挂载后注册事件
    onMounted(() => {
      nextTick(() => {
        registerEvents()
      })
    })
    
    // 组件卸载前清理事件
    onBeforeUnmount(() => {
      if (cleanup) {
        cleanup()
        cleanup = null
      }
      if (scrollCleanup) {
        scrollCleanup()
        scrollCleanup = null
      }
      // 确保键盘状态被重置
      markKeyboardClosed()
      // 停止键盘状态检测
      stopKeyboardCheck()
    })
  }

  return {
    hideKeyboard,
    registerEvents,
    isIOS: isIOS(),
    isAndroid: isAndroid(),
    isEdge,
    isKeyboardOpen
  }
}

export default useKeyboard 